/**
 * 封装请求
 */
import axios from 'axios'
import {ElMessage, ElLoading, ElMessageBox} from 'element-plus'

// 创建axios实例
const service = axios.create({
    baseURL: import.meta.env.VITE_API_BASE_URL,
    timeout: 30000, // 请求超时
    headers: {
        'Content-Type': 'application/json;charset=utf-8'
    }
})

// 加载动画实例
let loadingInstance = null
// 正在登录标识
let isLoggingIs = false
// 待重试的请求队列
const requestQueue = []

// 请求计数器
let requestCount = 0
// 延迟关闭定时器标识
let loadingTimer = null
// 显示加载动画
const showLoading = () => {
    // 如果当前正在延迟关闭，则清除
    if (loadingTimer) {
        clearTimeout(loadingTimer)
        loadingTimer = null
    }
    // 只有当计数器为0时，才创建新的实例
    if (requestCount === 0) {
        loadingInstance = ElLoading.service({
            lock: true,
            text: '加载中...',
            background: 'rgba(0, 0, 0, 0.1)'
        });
    }
    requestCount++
}
// 隐藏加载动画
const hideLoading = () => {
    // 请求计数-1
    requestCount--

    // 确保计数不会出现负数
    if (requestCount < 0) {
        requestCount = 0
    }
    // 只有当计数为0时才关闭加载
    if (requestCount === 0) {
        // 这里加个延迟，避免快速连续请求导致的闪烁
        loadingTimer = setTimeout(() => {
            if (loadingInstance) {
                loadingInstance.close()
                loadingInstance = null
            }
            loadingTimer = null
        }, 100);
    }
}

// 请求拦截
service.interceptors.request.use(
    (config) => {
        // 显示加载动画
        showLoading()

        // 在请求头中添加token
        const tokenName = localStorage.getItem("tokenName")
        const tokenValue = localStorage.getItem("tokenValue")
        if (tokenName !== undefined && tokenName !== '') {
            config.headers[tokenName] = tokenValue
        }

        return config
    },
    (error) => {
        // 关闭加载动画
        hideLoading()
        ElMessage.error('请求出错：' + error.message)
        return Promise.reject(error)
    }
)

// 响应拦截
service.interceptors.response.use(
    (response) => {
        // 关闭加载动画
        hideLoading()

        const {data, config} = response

        if (data.code !== 200) {
            if (data.code === 401) {
                ElMessage.error('未授权，请登录');
                // 排除登录接口
                if (config.url === '/login') {
                    return Promise.reject(response)
                }

                // 处理未登录逻辑
                return handleUnauthorizedRequest(config)
            } else {
                ElMessage.error(data.msg || '操作失败');
                return Promise.reject(new Error(data.msg || '操作失败'));
            }
        } else {
            return data
        }
    },
    (error) => {
        // 关闭加载动画
        hideLoading()

        // 处理不同状态码
        if (error.response) {
            switch (error.response.status) {
                case 401:
                    ElMessage.error('未授权，请登录')
                    break
                case 403:
                    ElMessage.error('拒绝访问')
                    break
                case 404:
                    ElMessage.error('请求地址不存在')
                    break
                case 500:
                    ElMessage.error('服务器内部错误')
                    break
                default:
                    ElMessage.error('请求失败：' + error.message)
            }
        } else {
            ElMessage.error('网络连接错误')
        }
        return Promise.reject(error)
    }
)

/**
 * 处理未登录逻辑
 * @param config
 */
function handleUnauthorizedRequest(config) {
    return new Promise((resolve, reject) => {
        // 将当前config、resolve、reject存入队列
        requestQueue.push({config, resolve, reject})

        // 若未在登录中，则触发登录
        if (!isLoggingIs) {
            isLoggingIs = true

            ElMessageBox.confirm(
                '你确认要登录吗?',
                '警告',
                {
                    confirmButtonText: '确认',
                    cancelButtonText: '取消',
                    type: 'warning',
                }
            ).then(() => {
                // 调用登录
                service.post('/test/login', {
                    username: 'admin',
                    password: '123'
                }).then((res) => {
                    // 登录成功
                    localStorage.setItem('tokenName', res.data.tokenName)
                    localStorage.setItem('tokenValue', res.data.tokenValue)
                    retryRequests()
                }).catch((err) => {
                    // 登录失败：拒绝队列中所有请求
                    rejectQueue(err)
                }).finally(() => {
                    // 重置登录状态
                    isLoggingIs = false
                })
            }).catch(() => {
                ElMessage({
                    type: 'info',
                    message: '用户取消登录',
                })
                rejectQueue()
            })
        }
    })
}

/**
 * 重试队列中的请求
 */
function retryRequests() {
    // 遍历队列，重新发起请求
    requestQueue.forEach(({config, resolve, reject}) => {
        // 重新发起请求，并将结果传递给原请求的resolve/reject
        service(config).then((res) => resolve(res)).catch((err) => reject(err))
    })
    // 清空队列
    requestQueue.length = 0
}

/**
 * 登录失败时拒绝队列
 * @param err
 */
function rejectQueue(err) {
    // 拒绝队列中所有请求
    requestQueue.forEach(({reject}) => {
        reject(err)
    })
    // 清空队列
    requestQueue.length = 0
}

export default service
